iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 25
0
Modern Web

用 Python 玩 PDF,結合Django 變成一個網頁系統系列 第 25

[Day 25] 前端顯示圖表(Chart.js)

  • 分享至 

  • xImage
  •  

昨天完成表格後,今天來寫前端顯示未來鄉鎮溫度折線圖和降雨機率長條圖,js 有很多畫圖表的套件,我這邊選Chart.js,Chart.js一個開源的套件,裡面有許多常見的圖表,長條圖、折線圖、圓餅圖等等,官網文件也滿清楚的。

一樣先寫Api,這裡就用同一個getPdfWeather(),多回傳一個chartTemperatureDict ,圖表格式,這裡也先把chart js 的資料處理好,前端js就直接撈就好。
ex

[{
    locationName: "文山區"
    tableDataList: ..., 
    chartTemperatureDict: {
        temperatureList: [24, 24, 26, 26, 24],
        aTemperatureList: [24, 24, 26, 26, 24],
        pop6HList: [20, 40, 20, 40],
    }
},
    locationName: "松山區"
    tableDataList: ..., 
    chartTemperatureDict: {
        temperatureList: [24, 24, 26, 26, 24],
        aTemperatureList: [24, 24, 26, 26, 24],
        pop6HList: [20, 40, 20, 40],
    }
}, 
]

main/views.py 局部程式碼

def convertChart(dataDict):
    todayDate = datetime.datetime.today().date()
    tomorrow = todayDate + datetime.timedelta(days=1)
    tomorrowText = tomorrow.strftime('%Y-%m-%d')
    showDateText = tomorrowText
    temperatureList = []
    for temperatureDict in dataDict["temperatureDictList"]:
        dataTime = temperatureDict["dataTime"]
        if showDateText in dataTime:
            temperatureList.append(temperatureDict['value'])
    aTemperatureList = [] # 省略
    
    pop6HList = []
    for pop6HDict in dataDict["pop6HDictList"]:
        startTime = pop6HDict["startTime"]
        if showDateText in startTime:
            pop6HList.append(pop6HDict['value'])
            pop6HList.append(pop6HDict['value'])
    return {
        "temperatureList": temperatureList,
        "aTemperatureList": aTemperatureList,
        "pop6HList": pop6HList,
    }

def getPdfWeather(request):
    ...
    for dataDict in dataDictList:
        resultList.append({
            "locationName": dataDict["locationName"],
            "tableDataList": convertToList(dataDict),
            "chartTemperatureDict": convertChart(dataDict)
        })

    return JsonResponse(resultList, safe=False)

main/main.html 局部程式碼,只列新增的

// render 折線圖的canvas,要設定不一樣的id
const renderLineChart = (dataObj) => {
        return `<canvas id="lineChart_${dataObj.locationName}" width="400" height="100"></canvas>`
    }
// render 長條圖的canvas,要設定不一樣的id
    const renderBarChart = (dataObj) => {
        return `<canvas id="barChart_${dataObj.locationName}" width="400" height="100"></canvas>`
    }
    
    const renderWeatherCard = (dataObj) => {
        return `
                <div class="card">
              <div class="card-header">
                ${dataObj.locationName}
              </div>
              <div class="card-body">
                ${renderTable(dataObj)}
                ${renderLineChart(dataObj)} // 多call
                ${renderBarChart(dataObj)}  // 多call
              </div>
        </div>
        `
    }
    // 產生折線圖物件
    const renderLineChartInit = (dataObj) => {
        let canvas = document.getElementById(`lineChart_${dataObj.locationName}`);
        let ctx = canvas.getContext('2d');
        let myLineChart = new Chart(ctx, {
            type: 'line',
            data: {
                labels: ["00:00", "03:00", "06:00", "09:00", "12:00", "15:00", "18:00", "21:00"],
                datasets: [{
                    label: '溫度',
                    backgroundColor: 'green',
                    borderColor: 'green',
                    data: dataObj.chartTemperatureDict.temperatureList,
                    fill: false,
                }, {
                    label: '體感溫度',
                    fill: false,
                    backgroundColor: 'blue',
                    borderColor: 'blue',
                    data: dataObj.chartTemperatureDict.aTemperatureList,
                }]
            },
            options: {
                responsive: true,
                title: {
                    display: true,
                    text: '未來鄉鎮溫度折線圖'
                },
                tooltips: {
                    mode: 'index',
                    intersect: false,
                },
                hover: {
                    mode: 'nearest',
                    intersect: true
                },
                scales: {
                    xAxes: [{
                        display: true,
                        scaleLabel: {
                            display: true,
                            labelString: '時間'
                        }
                    }],
                    yAxes: [{
                        display: true,
                        scaleLabel: {
                            display: true,
                            labelString: '溫度'
                        }
                    }]
                }
            }
        })
    }
    
    // 產生長條圖物件
    const renderBarChartInit = (dataObj) => {
        let canvas = document.getElementById(`barChart_${dataObj.locationName}`);
        let ctx = canvas.getContext('2d');
        let myLineChart = new Chart(ctx, {
            type: 'bar',
            data: {
                labels: ["00:00", "03:00", "06:00", "09:00", "12:00", "15:00", "18:00", "21:00"],
                datasets: [{
                    label: '降雨機率',
                    backgroundColor: 'lightblue',
                    borderColor: 'black',
                    borderWidth: 1,
                    data: dataObj.chartTemperatureDict.pop6HList,
                },]
            },
            options: {
                responsive: true,
                title: {
                    display: true,
                    text: '未來鄉鎮降雨機率長條圖'
                },
                scales: {
                    xAxes: [{
                        display: true,
                        scaleLabel: {
                            display: true,
                            labelString: '時間'
                        }
                    }],
                    yAxes: [{
                        ticks: {
                            beginAtZero: true,
                            min: 0,
                            max: 100,
                            steps: 10,
                        },
                        display: true,
                        scaleLabel: {
                            display: true,
                            labelString: '降雨機率%'
                        }
                    }]
                }
            }
        })
    }
    
    
    const reqGetPdfWeather = (selectedDistrictChxArr) => {
        ...
        $.ajax({
            url: `/api/getPdfWeather/?${queryString}`,
            processData: false,
            contentType: false,
            success: (res) => {
                res.map((dataObj) => {
                    $("#weatherDiv").append(renderWeatherCard(dataObj))
                    // 先有canvas,再寫chart
                    renderLineChartInit(dataObj) 
                    renderBarChartInit(dataObj)
                })
            }
        })
    }

結果圖 把圖表放在表格下方

結語
js 有點太長了,要重構寫到js檔案了


參考資料:

如果有任何寫得不好的地方,請跟我說,謝謝。


上一篇
[Day 24] 前端顯示表格
下一篇
[Day 26] PostgreSQL
系列文
用 Python 玩 PDF,結合Django 變成一個網頁系統30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言